﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using MiniErp.Core.Filters;
using MiniErp.Entity.JWTs;
using MiniErp.Mysql.Data;
using MiniErp.Repository.BaseRepository;
using MiniErp.Repository.MysqlRepository.IRepository;
using MiniErp.Repository.MysqlRepository.IRepository.AssetManagement;
using MiniErp.Repository.MysqlRepository.Repository;
using MiniErp.Repository.MysqlRepository.Repository.AssetManagement;
using MiniErp.Repository.UnitOfWorkCore;
using MiniErp.Service.AutoMapperService;
using MiniErp.Service.JWTService.IService;
using MiniErp.Service.JWTService.Service;
using MiniErp.Service.MysqlService.IService;
using MiniErp.Service.MysqlService.IService.IAssetManagement;
using MiniErp.Service.MysqlService.Service;
using MiniErp.Service.MysqlService.Service.AssetManagement;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace MiniErp.Core
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            #region DB业务
            services.AddDbContext<MysqlContext>(options =>
               options.UseMySQL(Configuration.GetConnectionString("DefaultConnection")));
            //注册仓储
            services.AddTransient<IAssetInfoRepository, AssetInfoRepository>();
            services.AddTransient<IAssetModificationRecordRepository, AssetModificationRecordRepository>();
            //注册服务
            services.AddTransient<IAssetIndexService, AssetIndexService>();
            services.AddTransient<ILoginService, LoginService>();
            //注册工作单元
            services.AddTransient<IMysqlUnitOfWork, MysqlUnitOfWork>();
            #endregion
            #region JWT业务
            services.AddTransient<ITokenService, TokenService>();
            services.Configure<JWTTokenOPotions>(Configuration.GetSection("JWTTokenOPotions"));
            var tokenOPotions = new JWTTokenOPotions();
            Configuration.Bind("JWTTokenOPotions", tokenOPotions);
            //注册Token权限
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,//是否验证Issuer
                    ValidateAudience = true,//是否验证Audience
                    ValidateLifetime = true,//是否验证失效时间
                    ValidateIssuerSigningKey = true,//是否验证SecurityKey
                    ValidAudience = tokenOPotions.Audience,
                    ValidIssuer = tokenOPotions.Issuer,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOPotions.SecurityKey))
                };
            });
            //动态获取数据库所有权限
            var Rights = new List<string>();
#pragma warning disable ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
            using (var dbcontext = services.BuildServiceProvider().GetRequiredService<MysqlContext>())
#pragma warning restore ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
            {
                try
                {
                    Rights = dbcontext.rights.Select(item => item.RightName).ToListAsync().Result;
                }
                catch
                {
                    Rights = new List<string> { "1" };
                }

            }

            //注册自定义策略权限拦截 ===》TokenHandler类
            services.AddTransient<IAuthorizationHandler, Filters.RoleHandlerFilter>();
            services.AddAuthorization(options =>
            {
                Rights.ForEach(item =>
                {
                    options.AddPolicy(item, policy =>
                    policy.Requirements.Add(new TokenRequirement(item)));
                });
            });

            #endregion
            //注册Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "MiniErp.Core", Version = "v1" });
                //添加安全定义
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "格式为：Bearer token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                //添加安全要求
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                    {
                        Reference=new OpenApiReference
                        {
                            Type=ReferenceType.SecurityScheme,
                            Id="Bearer"
                        }
                    },new string[]{ }
                    }
                });
                //Swagger显示方法体注释（右键项目=》属性=》建置=》隐藏警告改为1701;1702;1591，勾选XML文件档案）
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.XML";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });
            //注册AutoMapper
            services.AddAutoMapper(typeof(ProfileService));
            //注册Httpcontext
            services.AddHttpContextAccessor();


        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MiniErp.Core v1"));
            }

            app.UseHttpsRedirection();
            //启动鉴权
            app.UseAuthentication();
            //路由
            app.UseRouting();
            //启用自定义策略鉴权
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
